____ _ _ _ _
| _ \ ___ | |_ (_) _ __ ___ __| | (_) __ _
| |_) | / _ \ | __| | | | '_ \ / _ \ / _| | | | / _ |
| _ < | __/ | |_ | | | |_) | | __/ | (_| | | | | (_| |
|_| \_\ \___| \__| |_| | .__/ \___| \__,_| |_| \__,_|
|_|
- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b- `b
Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―Β―
Steinscher Algorithmus
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
top
Der steinsche Algorithmus oder binΓ€re euklidische Algorithmus dient der effizienten Berechnung des grΓΆΓten gemeinsamen Teilers. Der Algorithmus wurde 1967 vom Physiker Josef Stein (HebrΓ€ische UniversitΓ€t Jerusalem) vorgestellt.cite-ref-1[1] Donald E. Knuth zufolge entwickelten R. Silver und J. Tersian den Algorithmus bereits 1962, publizierten ihn aber nicht.cite-ref-knuth-2-0[2]
Contents
β’ Funktionsweise
β’ Prinzip
β’ Algorithmus
β’ Quellen
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Funktionsweise
Der Algorithmus nutzt folgende Rechenregeln:
Falls b = 0 {\displaystyle b=0} :
β’ ggT β‘ β‘ ( a , 0 ) = a {\displaystyle \operatorname {ggT} (a,\ 0)=a\qquad } und Haltebedingung des Algorithmus
Falls b = ungerade {\displaystyle b={\text{ungerade}}} :
β’ ggT β‘ β‘ ( a , b ) = { ggT β‘ β‘ ( a , b β β a ) falls b β₯ β₯ a ggT β‘ β‘ ( b , a β β b ) sonst {\displaystyle \operatorname {ggT} (a,\ b)={\begin{cases}\operatorname {ggT} (a,\ b-a)\ \ \quad &{\text{falls }}b\geq a\\\operatorname {ggT} (b,\ a-b)\ \ \quad &{\text{sonst }}\end{cases}}}
Falls b = gerade {\displaystyle b={\text{gerade}}} :
β’ ggT β‘ β‘ ( a , b ) = { ggT β‘ β‘ ( a , b / 2 ) falls a ungerade ggT β‘ β‘ ( a / 2 , b / 2 ) β
β
2 sonst {\displaystyle \operatorname {ggT} (a,\ b)={\begin{cases}\operatorname {ggT} (a,\ b/2)&{\text{falls }}a{\text{ ungerade}}\\\operatorname {ggT} (a/2,\ b/2)\cdot 2&{\text{sonst }}\end{cases}}}
Funktionsweise
a) Nutzt ggT β‘ β‘ ( a , 0 ) = a {\displaystyle \operatorname {ggT} (a,\ 0)=a\ } aus und ist gleichzeitig die Haltebedingung des Algorithmus.
b) Wird abgewendet, wenn b {\displaystyle b} ungerade ist. b1) Ist b β₯ β₯ a {\displaystyle b\geq a} , wird b {\displaystyle b} um a {\displaystyle a} reduziert. ggT β‘ β‘ ( a , b ) = ggT β‘ β‘ ( a , b β β a ) {\displaystyle \operatorname {ggT} (a,\ b)=\operatorname {ggT} (a,\ b-a)} ausgenutzt. b2) Ist b < a {\displaystyle b<a} , wird als erster Operand der zweite Operand b {\displaystyle b} benutzt und als zweiter Operand a β β b {\displaystyle a-b} . Durch dieses geschickte Umsortieren wird das Horrorszenario des klassischen euklidischen Algorithmus vermieden, in dem ein sehr groΓer Operand nur sehr langsam reduziert wird.
c) wird verwendet, wenn b {\displaystyle b} gerade ist: c1) Wenn nur ein Operand gerade ist, kann die 2 {\displaystyle 2} als gemeinsamer Teiler gestrichen werden. c2) Wenn beide Operanden gerade ist, werde beide um den Teiler 2 {\displaystyle 2} verringert, diese Operation wird sich aber fΓΌr das Endergebnis gemerkt, da es ja ein gemeinsamer Teiler ist.
Wir benutzen dafΓΌr das Horrorszenario fΓΌr den klassischen euklidischen Algorithmus, zwei groΓe fast gleiche Zahlen 209865 {\displaystyle 209865} und 209797 {\displaystyle 209797} :
ggT β‘ β‘ ( 209865 , 209797 ) = ggT β‘ β‘ ( 209797 , 68 ) b2 ggT β‘ β‘ ( 209797 , 68 ) = ggT β‘ β‘ ( 209797 , 34 ) c1 ggT β‘ β‘ ( 209797 , 34 ) = ggT β‘ β‘ ( 209797 , 17 ) c1 ggT β‘ β‘ ( 209797 , 17 ) = ggT β‘ β‘ ( 17 , 209780 ) b2, hier bekommt der klassische euklidische Algorithmus ein Problem, hier wird allerdings eine ungerade Zahl durch Division durch 2 erzeugt und diese nach vorn gebracht ggT β‘ β‘ ( 17 , 209780 ) = ggT β‘ β‘ ( 17 , 104890 ) c1, hier wird entweder halbiert oder diese ungerade Zahl subtrahiert und damit eine gerade Zahl erzeugt ggT β‘ β‘ ( 17 , 104890 ) = ggT β‘ β‘ ( 17 , 52445 ) c1 ggT β‘ β‘ ( 17 , 52445 ) = ggT β‘ β‘ ( 17 , 52428 ) b1 ggT β‘ β‘ ( 17 , 52428 ) = ggT β‘ β‘ ( 17 , 26214 ) c1 ggT β‘ β‘ ( 17 , 26214 ) = ggT β‘ β‘ ( 17 , 13107 ) c1 ggT β‘ β‘ ( 17 , 13107 ) = ggT β‘ β‘ ( 17 , 13090 ) b1 ggT β‘ β‘ ( 17 , 13090 ) = ggT β‘ β‘ ( 17 , 6545 ) c1 ggT β‘ β‘ ( 17 , 6545 ) = ggT β‘ β‘ ( 17 , 6528 ) b1 ggT β‘ β‘ ( 17 , 6528 ) = ggT β‘ β‘ ( 17 , 3264 ) c1 ggT β‘ β‘ ( 17 , 3264 ) = ggT β‘ β‘ ( 17 , 1632 ) c1 ggT β‘ β‘ ( 17 , 1632 ) = ggT β‘ β‘ ( 17 , 816 ) c1 ggT β‘ β‘ ( 17 , 816 ) = ggT β‘ β‘ ( 17 , 408 ) c1 ggT β‘ β‘ ( 17 , 408 ) = ggT β‘ β‘ ( 17 , 204 ) c1 ggT β‘ β‘ ( 17 , 204 ) = ggT β‘ β‘ ( 17 , 102 ) c1 ggT β‘ β‘ ( 17 , 102 ) = ggT β‘ β‘ ( 17 , 51 ) c1 ggT β‘ β‘ ( 17 , 51 ) = ggT β‘ β‘ ( 17 , 34 ) b1 ggT β‘ β‘ ( 17 , 34 ) = ggT β‘ β‘ ( 17 , 17 ) c1 ggT β‘ β‘ ( 17 , 17 ) = ggT β‘ β‘ ( 17 , 0 ) b1 ggT β‘ β‘ ( 17 , 0 ) = 17 a {\displaystyle {\begin{array}{rl|l}\operatorname {ggT} (209865,\ 209797)&=\operatorname {ggT} (209797,\ 68)&\scriptstyle {\text{b2}}\\\operatorname {ggT} (209797,\ 68)&=\operatorname {ggT} (209797,\ 34)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (209797,\ 34)&=\operatorname {ggT} (209797,\ 17)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (209797,\ 17)&=\operatorname {ggT} (17,\ 209780)&\scriptstyle {\text{b2, hier bekommt der klassische euklidische Algorithmus ein Problem, hier wird allerdings eine ungerade Zahl durch Division durch 2 erzeugt und diese nach vorn gebracht}}\\\operatorname {ggT} (17,\ 209780)&=\operatorname {ggT} (17,\ 104890)&\scriptstyle {\text{c1, hier wird entweder halbiert oder diese ungerade Zahl subtrahiert und damit eine gerade Zahl erzeugt}}\\\operatorname {ggT} (17,\ 104890)&=\operatorname {ggT} (17,\ 52445)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 52445)&=\operatorname {ggT} (17,\ 52428)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 52428)&=\operatorname {ggT} (17,\ 26214)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 26214)&=\operatorname {ggT} (17,\ 13107)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 13107)&=\operatorname {ggT} (17,\ 13090)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 13090)&=\operatorname {ggT} (17,\ 6545)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 6545)&=\operatorname {ggT} (17,\ 6528)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 6528)&=\operatorname {ggT} (17,\ 3264)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 3264)&=\operatorname {ggT} (17,\ 1632)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 1632)&=\operatorname {ggT} (17,\ 816)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 816)&=\operatorname {ggT} (17,\ 408)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 408)&=\operatorname {ggT} (17,\ 204)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 204)&=\operatorname {ggT} (17,\ 102)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 102)&=\operatorname {ggT} (17,\ 51)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 51)&=\operatorname {ggT} (17,\ 34)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 34)&=\operatorname {ggT} (17,\ 17)&\scriptstyle {\text{c1}}\\\operatorname {ggT} (17,\ 17)&=\operatorname {ggT} (17,\ 0)&\scriptstyle {\text{b1}}\\\operatorname {ggT} (17,\ 0)&=17&\scriptstyle {\text{a}}\\\end{array}}}
Zu beachten ist, dass der steinsche Algorithmus nur dann richtig funktioniert, wenn vorzeichenlose Integer verwendet werden. Negative Zahlen mΓΌssen zuerst in positive ΓΌberfΓΌhrt werden. Der euklidische Algorithmus hingegen funktioniert auch mit vorzeichenbehafteten Integertypen, wenn ein Operand nicht die kleinste darstellbare Zahl ist.
Prinzip
Zu bestimmen sei der grΓΆΓte gemeinsame Teiler der beiden positiven Zahlen a {\displaystyle a} und b {\displaystyle b} . Dazu wird als erstes eine Variable k {\displaystyle k} definiert und dieser wird der Wert 0 zugewiesen. Dann werden sowohl a {\displaystyle a} als auch b {\displaystyle b} solange durch 2 geteilt, bis a {\displaystyle a} und b {\displaystyle b} nicht mehr durch 2 teilbar sind. Bei jeder Halbierung wird k {\displaystyle k} um 1 erhΓΆht.
Der zweite Teil benΓΆtigt eine zusΓ€tzliche Variable t {\displaystyle t} , der die Differenz von a {\displaystyle a} und b {\displaystyle b} zugewiesen wird. Jeder gemeinsame Teiler von a {\displaystyle a} und b {\displaystyle b} ist auch Teiler von t {\displaystyle t} , sodass gilt: ggT β‘ β‘ ( a , b ) = ggT β‘ β‘ ( a , t ) = ggT β‘ β‘ ( b , t ) {\displaystyle \operatorname {ggT} (a,b)=\operatorname {ggT} (a,t)=\operatorname {ggT} (b,t)} . Die Variable t {\displaystyle t} wird anschlieΓend noch, solange es sich um eine gerade Zahl handelt, durch 2 geteilt. Dann wird a {\displaystyle a} durch t {\displaystyle t} ersetzt und mit dem neuen a {\displaystyle a} ein neues t {\displaystyle t} berechnet. Der Algorithmus ist beendet, sobald t = 0 {\displaystyle t=0} gilt. Das Ergebnis ist dann ggT β‘ β‘ ( a , b ) = a β
β
2 k {\displaystyle \operatorname {ggT} (a,b)=a\cdot 2^{k}} .cite-ref-3[3]
Algorithmus
Die hier in Pseudocode beschriebene Variante des Algorithmus entspricht im Wesentlichen derjenigen, die Donald E. Knuth in seinem Werk The Art of Computer Programming beschreibt.
STEIN(a,b)
wenn a = 0
dann return b
k
β
{\displaystyle \leftarrow }
0
solange a und b gerade Zahlen sind
a
β
{\displaystyle \leftarrow }
a/2
b
β
{\displaystyle \leftarrow }
b/2
k
β
{\displaystyle \leftarrow }
k + 1
wenn a eine ungerade Zahl ist
dann t
β
{\displaystyle \leftarrow }
-b
sonst t
β
{\displaystyle \leftarrow }
a
solange t β 0
solange t eine gerade Zahl ist
t
β
{\displaystyle \leftarrow }
t/2
wenn t > 0
dann a
β
{\displaystyle \leftarrow }
t
sonst b
β
{\displaystyle \leftarrow }
-t
t
β
{\displaystyle \leftarrow }
a - b
return a
β
{\displaystyle \cdot }
2k
Viele Prozessoren haben heutzutage BefehlssΓ€tze, die sehr schnell (oft in einem Takt) bestimmen kΓΆnnen, wie oft eine Ganzzahl durch Zwei teilbar ist. Zum Beispiel stellt die x86-Architektur seit dem 80386 fΓΌr diesen Zweck die Instruktion bsf zur VerfΓΌgung. Unter Verwendung einer solchen Instruktion ist es mΓΆglich, zwei der drei Schleifen des Algorithmus einzusparen und damit seine Laufzeit signifikant zu verbessern. Die folgende Implementierung in der Programmiersprache C nutzt zu diesem Zwecke die POSIX-Standardfunktion ffs (find first set):
#include <stdlib.h> /* fΓΌr abs() */
#include <strings.h> /* fΓΌr ffs() */
int ggt(int a, int b)
{
int c;
if (a == 0 || b == 0) // falls eines oder beide Argumente 0 sind,
return a | b; // ist das andere Argument oder 0 das Ergebnis
// dies kann weggelassen werden, wenn a und b nicht negativ sein kΓΆnnen
a = abs(a);
b = abs(b);
c = ffs(a | b) - 1;
a >>= ffs(a) - 1;
do {
b >>= ffs(b) - 1;
if (a > b) {
// vertausche Variablen, damit bei Subtraktion kein Γberlauf stattfinden kann
int temp = b;
b = a;
a = temp;
}
b -= a;
} while (b != 0);
return a << c;
}
ggt:
mov ecx, 4[esp] ; Lade a
mov eax, 8[esp] ; Lade b
test ecx, ecx ; Vergleiche a mit 0:
jz done ; falls a gleich 0 ist das Ergebnis b
cmp eax, ecx ; Vergleiche a mit b:
je done ; falls a gleich b ist das Ergebnis b
mov edx, eax ; Lade b
mov eax, ecx ; Lade a
test edx, edx ; Vergleiche b mit 0:
jz done ; falls b gleich 0 ist das Ergebnis a
push ebx
bsf ecx, edx ; Bestimme grΓΆΓte Zweierpotenz von b
bsf ebx, eax ; Bestimme grΓΆΓte Zweierpotenz von a
cmp ebx, ecx ; Vergleiche beide
cmova ebx, ecx ; und merke deren Minimum
shr edx, cl ; Dividiere b durch grΓΆΓte Zweierpotenz
next:
bsf ecx, eax ; Bestimme grΓΆΓte Zweierpotenz von a
shr eax, cl ; Dividiere a durch grΓΆΓte Zweierpotenz
mov ecx, edx
cmp edx, eax ; Vergleiche b mit a
cmovb edx, eax ; und vertausche beide, falls b kleiner a
cmovb eax, ecx
sub edx, eax ; Subtrahiere a von b
jnz next ; und wiederhole, bis b gleich 0
mov ecx, ebx
shl eax, cl ; Multipliziere a mit 2**Minimum
pop ebx
done:
ret
Quellen
cite-note-knuth-22. β Donald E. Knuth: The Art of Computer Programming. Band 2: Seminumerical Algorithms. 3. Auflage. Addison-Wesley Professional, 1997, ISBN 0-201-89684-2, S. 338β341.
cite-note-33. β Alexander Weers: GrΓΆΓter gemeinsamer Teiler. In: Formelsammlung24.de. Archiviert vom Original am 28. MΓ€rz 2018; abgerufen am 27. MΓ€rz 2018.